using System;
using System.Collections.Generic;
using PingPong.Generic;
using PingPong.GameEngine.Components;
using PingPong.Generic.Helpers;

namespace PingPong.GameEngine
{
	public class GameDefinition
	{
		#region Members

		/// <summary>
		/// The name of the game definition.
		/// </summary>
		private Lazy<string> gameDefinitionName;
		/// <summary>
		/// The team rotation type.
		/// </summary>
		private Lazy<TeamRotationType> teamRotationType;
		/// <summary>
		/// The type of the scoring.
		/// </summary>
		private Lazy<ScoringType> scoringType;
		/// <summary>
		/// The team count.
		/// </summary>
		private Lazy<string> teamCountExpression;
		/// <summary>
		/// The size of the team.
		/// </summary>
		private Lazy<string> teamSizeExpression;
		/// <summary>
		/// The game events.
		/// </summary>
		private Lazy<List<GameEvent>> gameEvents;
		/// <summary>
		/// The errors.
		/// </summary>
		private Lazy<List<Parser.Error>> errors;

		#endregion

		#region Properties

		/// <summary>
		/// Gets the name of the game definition.
		/// </summary>
		/// <value>The name of the game definition.</value>
		public string GameDefinitionName
		{
			get
			{
				return this.gameDefinitionName.Value;
			}
		}

		/// <summary>
		/// Gets the type of the team rotation.
		/// </summary>
		/// <value>The type of the team rotation.</value>
		public TeamRotationType TeamRotationType
		{
			get
			{
				return this.teamRotationType.Value;
			}
		}

		/// <summary>
		/// Gets the type of the scoring.
		/// </summary>
		/// <value>The type of the scoring.</value>
		public ScoringType ScoringType
		{
			get
			{
				return this.scoringType.Value;
			}
		}

		/// <summary>
		/// Gets the team count.
		/// </summary>
		/// <value>The team count.</value>
		public int TeamCount
		{
			get
			{
				Engine.ExpressionParser.Interpret(this.teamCountExpression.Value);
				return Engine.ExpressionParser.Int;
			}
		}

		/// <summary>
		/// Gets the size of the team.
		/// </summary>
		/// <value>The size of the team.</value>
		public int TeamSize
		{
			get
			{
				Engine.ExpressionParser.Interpret(this.teamSizeExpression.Value);
				return Engine.ExpressionParser.Int;
			}
		}

		/// <summary>
		/// Gets the game event list.
		/// </summary>
		/// <value>The game event list.</value>
		private List<GameEvent> GameEventList
		{
			get
			{
				return this.gameEvents.Value;
			}
		}

		/// <summary>
		/// Gets the game events.
		/// </summary>
		/// <value>The game events.</value>
		public IEnumerable<GameEvent> GameEvents
		{
			get
			{
				return this.GameEventList;
			}
		}

		/// <summary>
		/// Gets the error list.
		/// </summary>
		/// <value>The error list.</value>
		private List<Parser.Error> ErrorList
		{
			get
			{
				return this.errors.Value;
			}
		}

		/// <summary>
		/// Gets the errors.
		/// </summary>
		/// <value>The errors.</value>
		public IEnumerable<Parser.Error> Errors
		{
			get
			{
				return this.ErrorList;
			}
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="PingPong.GameEngine.GameDefinition"/> class.
		/// </summary>
		public GameDefinition()
		{
			this.gameDefinitionName = new Lazy<string>(() => string.Empty);
			this.teamRotationType = new Lazy<TeamRotationType>(() => TeamRotationType.None);
			this.scoringType = new Lazy<ScoringType>(() => ScoringType.None);
			this.teamCountExpression = new Lazy<string>(() => string.Empty);
			this.teamSizeExpression = new Lazy<string>(() => string.Empty);
			this.gameEvents = new Lazy<List<GameEvent>>(() => new List<GameEvent>());
			this.errors = new Lazy<List<Parser.Error>>(() => new List<Parser.Error>());
		}

		#endregion

		#region Methods

		/// <summary>
		/// Sets the name of the game definition.
		/// </summary>
		/// <returns>The game definition name.</returns>
		/// <param name="definitionName">Definition name.</param>
		public GameDefinition SetGameDefinitionName(string definitionName)
		{
			this.gameDefinitionName = new Lazy<string>(() => definitionName);
			return this;
		}

		/// <summary>
		/// Sets the type of the team rotation.
		/// </summary>
		/// <returns>The team rotation type.</returns>
		/// <param name="teamRotationType">Team rotation type.</param>
		public GameDefinition SetTeamRotationType(TeamRotationType teamRotationType)
		{
			this.teamRotationType = new Lazy<TeamRotationType>(() => teamRotationType);
			return this;
		}

		/// <summary>
		/// Sets the type of the scoring.
		/// </summary>
		/// <returns>The scoring type.</returns>
		/// <param name="scoringType">Scoring type.</param>
		public GameDefinition SetScoringType(ScoringType scoringType)
		{
			this.scoringType = new Lazy<ScoringType>(() => scoringType);
			return this;
		}

		/// <summary>
		/// Sets the team count.
		/// </summary>
		/// <returns>The team count.</returns>
		/// <param name="expression">Expression.</param>
		public GameDefinition SetTeamCount(string expression)
		{
			this.teamCountExpression = new Lazy<string>(() => expression);
			return this;
		}

		/// <summary>
		/// Sets the size of the team.
		/// </summary>
		/// <returns>The team size.</returns>
		/// <param name="expression">Expression.</param>
		public GameDefinition SetTeamSize(string expression)
		{
			this.teamSizeExpression = new Lazy<string>(() => expression);
			return this;
		}

		/// <summary>
		/// Adds the game event.
		/// </summary>
		/// <returns>The game event.</returns>
		/// <param name="gameEvent">Game event.</param>
		public GameDefinition AddGameEvent(GameEvent gameEvent)
		{
			this.GameEventList.Add(gameEvent);
			return this;
		}

		/// <summary>
		/// Sets the errors.
		/// </summary>
		/// <returns>The errors.</returns>
		/// <param name="errors">Errors.</param>
		public GameDefinition SetErrors(IEnumerable<Parser.Error> errors)
		{
			this.errors = new Lazy<List<Parser.Error>>(() => new List<Parser.Error>(errors));
			return this;
		}

		#endregion
	}
}

